#ifndef __TDP2_LIVERESOURCE_HPP__
#define __TDP2_LIVERESOURCE_HPP__

#include "../../rdx/src/rdx/rdx_basictypes.hpp"

namespace TDP
{
	namespace Resources
	{
		typedef RDX::LargeInt LiveResourceHandle;
	}

	namespace Rendering
	{
		struct IRenderDevice;
		typedef RDX::LargeInt RenderTextureHandle;
		typedef RDX::LargeInt RenderShaderHandle;
	}
}

#include "tdp2.hpp"
#include "tdp2_allocator.hpp"
#include "tdp2_visualresources.hpp"
#include "tdp2_vector.hpp"
#include "tdp2_visualresources_enums.hpp"

namespace TDP
{
	class PanicHandler;
	class MainContext;

	namespace ResourceManagement
	{
		class ResourcePreloader;
	}

	namespace Resources
	{
		class LiveResource;
		struct StreamableResource;
		class LiveResourceManager;

		struct LiveResourceLink
		{
			LiveResource *resource;
			LiveResourceLink *nextFree;
		};

		class LiveResource
		{
		public:
			bool _initialized;

		private:
			ResourceType _resourceType;
		public:
			LiveResource();
			virtual bool DigestStreamData(const void *data, LargeUInt numBytesAvailable, LargeUInt *outNumDigested) = 0;
			virtual ~LiveResource() = 0;

			inline ResourceType ResourceType() const
			{
				return _resourceType;
			}
		};

		class LiveResourceManager
		{
			RDX::ObjectManagement::Allocator _alloc;
			LargeInt _numResources;
			TDP::Containers::Vector<LiveResourceLink> _lrLinks;
			TDP::Containers::Vector<Byte> _preloadBlock;
			LargeInt _preloadNumBytes;
			LiveResourceLink *_firstFree;
			TDP::MainContext *_mainContext;

			LargeInt _bundleResourceIndex;
			bool _bundleResourceStarted;

		public:
			LiveResourceManager(RDX::ObjectManagement::Allocator &alloc, TDP::MainContext *mainContext);
			bool Initialize(LargeInt maxResources, LargeInt maxBlockSize);

			LiveResourceHandle CreateTexture(TextureSpec::TextureFormat tf,
				TextureSpec::TextureLayout tl, Int numMipMaps, Int cachedMipMaps,
				Int width, Int height, Int depth, UInt32 flags);
			LiveResourceHandle CreateCompiledShader(ShaderSpec::ShaderType, LargeUInt sizeBytes);
			bool TryStream(ResourceManagement::ResourcePreloader *preloader, Resources::StreamableResource *sr);
			void BeginStreamingResource(ResourceManagement::ResourcePreloader *preloader, Resources::StreamableResource *sr, bool fromBundle);
			void ReleaseLRH(LiveResourceHandle lrh);
			LiveResourceHandle CreateLRH(size_t dataSize, size_t dataAlign);

			LiveResource *MapLRH(LiveResourceHandle lrh);		// Accesses the memory of a LRH.  CreateLRH should never be called while using a mapped handle.

			~LiveResourceManager();
		};

		struct LiveTextureResourceLOD
		{
			Rendering::RenderTextureHandle rth;
			UInt32 width, height, depth, numLevels, levelsLoaded;
		};

		class LiveCompiledShaderResource : public LiveResource
		{
			Rendering::RenderShaderHandle _rsh;
			bool _isCommitted;
			ShaderSpec::ShaderType _shaderType;
			void *_preloadBuffer;
			LargeUInt _bytesTotal;
			LargeUInt _bytesLoaded;
			Rendering::IRenderDevice *_device;
			RDX::ObjectManagement::Allocator _alloc;

		public:
			LiveCompiledShaderResource(Rendering::IRenderDevice *device, const RDX::ObjectManagement::Allocator &alloc, ShaderSpec::ShaderType st, LargeUInt sizeBytes);
			~LiveCompiledShaderResource();

			bool IsUploaded() const;

			bool DigestStreamData(const void *data, LargeUInt numBytesAvailable, LargeUInt *outNumDigested);
			void StartStreaming();
		};

		class LiveTextureResource : public LiveResource
		{
			TextureSpec::TextureFormat _texFormat;
			TextureSpec::TextureLayout _texLayout;
			Int _numMipMaps;
			Int _cachedMipMaps;
			UInt32 _width;
			UInt32 _height;
			UInt32 _depth;
			UInt32 _lowWidth;
			UInt32 _lowHeight;
			UInt32 _lowDepth;
			UInt32 _flags;

			UInt32 _pendingX, _pendingY, _pendingZ, _pendingSide;

			Rendering::IRenderDevice *_device;

			// The live texture LODs are NEVER the same texture.  If pending LOD obsoletes high LOD, then high LOD is simply destroyed
			LiveTextureResourceLOD _lowLOD;					// Low-resolution permanently resident texture
			LiveTextureResourceLOD _pendingLOD;				// Pending LOD, will replace highLOD or lowLOD when more levels are loaded or it finishes
			LiveTextureResourceLOD _highLOD;				// High-resolution LOD, only exists if numMipMaps > cachedMipMaps

			UInt32 ReduceDepth(UInt32 levels);

		public:
			LiveTextureResource(Rendering::IRenderDevice *device, TextureSpec::TextureFormat tf,
				TextureSpec::TextureLayout tl, Int numMipMaps, Int cachedMipMaps,
				Int width, Int height, Int depth, UInt32 flags);
			~LiveTextureResource();

			Rendering::RenderTextureHandle BestLOD() const;

			bool DigestStreamData(const void *data, LargeUInt numBytesAvailable, LargeUInt *outNumDigested);
			void StartStreaming(ResourceManagement::ResourcePreloader *preloader, UInt32 levelTarget);
		};
	}
}

inline RDX::UInt32 TDP::Resources::LiveTextureResource::ReduceDepth(RDX::UInt32 levels)
{
	if(_depth == 1)
		return 1;
	return _depth >> levels;
}


#endif
